package cn.time1024.time_app.ui.home

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import cn.time1024.time_app.R
import android.widget.Button
import android.widget.EditText
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import android.app.DownloadManager
import android.net.Uri
import android.os.Environment
import android.content.Intent
import android.webkit.URLUtil
import android.util.Log

import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.net.HttpURLConnection
import java.net.URL
import org.json.JSONObject
import cn.time1024.time_app.ui.player.VideoPlayerActivity

/**
 * 抖音视频下载页面：
 * - 输入抖音分享文案或链接，调用 Coze Workflow 解析视频直链；
 * - 解析成功后显示下载按钮，通过 DownloadManager 保存至系统下载目录；
 * - 全流程包含进度与提示，确保良好用户体验。
 */
class FeatureTwoFragment : Fragment() {
    private var downloadUrl: String? = null
    private val TAG = "DouyinDL"

    /**
     * 加载并返回页面布局。
     * - 初始化输入框、解析与下载按钮。
     * - 绑定长耗时解析请求的进度反馈与按钮状态。
     */
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val root = inflater.inflate(R.layout.fragment_feature_two, container, false)

        val etInput = root.findViewById<EditText>(R.id.etInput)
        val btnParse = root.findViewById<Button>(R.id.btnParse)
        val btnDownload = root.findViewById<Button>(R.id.btnDownload)
        val btnPlay = root.findViewById<Button>(R.id.btnPlay)
        val tvResult = root.findViewById<TextView>(R.id.tvResult)
        val progress = root.findViewById<ProgressBar>(R.id.progress)

        btnParse.setOnClickListener {
            val input = etInput.text?.toString()?.trim().orEmpty()
            if (input.isEmpty()) {
                Toast.makeText(requireContext(), "请输入抖音分享文案或链接", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            tvResult.text = ""
            btnDownload.isEnabled = false
            btnPlay.isEnabled = false
            progress.visibility = View.VISIBLE
            btnParse.isEnabled = false
            // 后台线程执行解析请求
            Thread {
                val url = runWorkflow(input)
                requireActivity().runOnUiThread {
                    progress.visibility = View.GONE
                    btnParse.isEnabled = true
                    if (url.isNullOrEmpty()) {
                        Toast.makeText(requireContext(), "解析失败，请稍后重试", Toast.LENGTH_SHORT).show()
                    } else {
                        downloadUrl = url
                        tvResult.text = url
                        btnDownload.isEnabled = true
                        btnPlay.isEnabled = true
                        Toast.makeText(requireContext(), "解析成功", Toast.LENGTH_SHORT).show()
                    }
                }
            }.start()
        }

        btnDownload.setOnClickListener {
            val url = downloadUrl
            if (url.isNullOrEmpty()) {
                Toast.makeText(requireContext(), "请先解析获取下载地址", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            startDownload(url)
        }

        btnPlay.setOnClickListener {
            val url = downloadUrl
            if (url.isNullOrEmpty()) {
                Toast.makeText(requireContext(), "请先解析获取播放地址", Toast.LENGTH_SHORT).show()
                return@setOnClickListener
            }
            openPlayer(url)
        }

        return root
    }

    /**
     * 打开视频播放器页面，在线播放视频直链。
     */
    private fun openPlayer(url: String) {
        try {
            val intent = Intent(requireContext(), VideoPlayerActivity::class.java)
            intent.putExtra(VideoPlayerActivity.EXTRA_URL, url)
            startActivity(intent)
        } catch (e: Exception) {
            Toast.makeText(requireContext(), "无法打开播放器：${e.message}", Toast.LENGTH_SHORT).show()
        }
    }

    /**
     * 调用 Coze Workflow 解析抖音链接，返回视频直链。
     * - 使用 HttpURLConnection 发送 POST 请求。
     * - 兼容 data 为 JSON 字符串或对象两种返回格式。
     */
    private fun runWorkflow(input: String): String? {
        val endpoint = "https://api.coze.cn/v1/workflow/run"
        val token = "Bearer cztei_hsb0CBrbz635BKtxPMF14kIiVDVU2aa2PQV3wr4MiUMeqKfQ6SzA3ZseUKLk9UbNB"
        val payload = JSONObject().apply {
            put("workflow_id", "7566644107989516331")
            val params = JSONObject().apply { put("input", input) }
            put("parameters", params)
        }
        val url = URL(endpoint)
        val conn = url.openConnection() as HttpURLConnection
        conn.requestMethod = "POST"
        conn.setRequestProperty("Authorization", token)
        conn.setRequestProperty("Content-Type", "application/json")
        conn.setRequestProperty("Accept", "application/json")
        conn.connectTimeout = 15000
        conn.readTimeout = 30000
        conn.doOutput = true
        try {
            Log.d(TAG, "runWorkflow: url=$endpoint, workflow_id=${payload.optString("workflow_id")}, input.length=${input.length}")
            OutputStreamWriter(conn.outputStream).use { it.write(payload.toString()) }
            val code = conn.responseCode
            val ct = conn.getHeaderField("Content-Type")
            val stream = if (code in 200..299) conn.inputStream else conn.errorStream
            val body = BufferedReader(InputStreamReader(stream)).use { it.readText() }
            Log.d(TAG, "runWorkflow: status=$code, contentType=$ct, body.size=${body.length}, body.sample=${body.take(512)}")
            if (code !in 200..299) {
                Log.e(TAG, "runWorkflow: non-2xx response; abort parse")
                return null
            }
            val root = try { JSONObject(body) } catch (e: Exception) {
                Log.e(TAG, "runWorkflow: invalid JSON root, err=${e.message}")
                return null
            }
            // 可能返回 { code, msg, data: "{\"output\":\"url\"}" }
            val dataAny = root.opt("data")
            val obj = when (dataAny) {
                is JSONObject -> dataAny
                is String -> runCatching { JSONObject(dataAny) }.onFailure { Log.e(TAG, "runWorkflow: parse data string failed: ${it.message}") }.getOrNull()
                else -> null
            }
            if (obj == null) {
                Log.e(TAG, "runWorkflow: data is null or unsupported type -> $dataAny")
                return null
            }
            val output = obj.optString("output").takeIf { it.isNotBlank() }
            Log.d(TAG, "runWorkflow: output=$output")
            return output
        } catch (e: Exception) {
            Log.e(TAG, "runWorkflow: exception=${e.javaClass.simpleName}, msg=${e.message}")
            return null
        } finally {
            conn.disconnect()
        }
    }

    /**
     * 使用 DownloadManager 下载视频（带预检优化）。
     * - 预检响应头获取 content-type、content-disposition，智能推断文件名与MIME。
     * - 若为 HLS(m3u8) 流，则引导直接播放，避免下载无效文件。
     * - 为部分源增加常用请求头（User-Agent/Referer/Accept），提高成功率。
     */
    private fun startDownload(url: String) {
        Thread {
            try {
                val head = fetchHeadInfo(url)
                val contentType = (head?.contentType ?: "").lowercase()
                Log.d(TAG, "download head: finalUrl=${head?.url}, contentType=$contentType, dispo=${head?.contentDisposition}")
                if (contentType.contains("mpegurl") || contentType.contains("application/vnd.apple.mpegurl") || url.contains(".m3u8")) {
                    requireActivity().runOnUiThread {
                        Toast.makeText(requireContext(), "检测到m3u8流，已为您切换为在线播放", Toast.LENGTH_LONG).show()
                        openPlayer(url)
                    }
                    return@Thread
                }

                val fileName = guessMp4FileName(url, head?.contentDisposition, contentType)
                val mime = if (contentType.startsWith("video/")) contentType else "video/mp4"
                Log.d(TAG, "download enqueue: fileName=$fileName, mime=$mime")

                val dm = requireContext().getSystemService(android.content.Context.DOWNLOAD_SERVICE) as DownloadManager
                val req = DownloadManager.Request(Uri.parse(url))
                    .setTitle("抖音视频")
                    .setDescription("正在下载抖音视频")
                    .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                    .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
                    .setAllowedOverMetered(true)
                    .setAllowedOverRoaming(true)
                    .setMimeType(mime)
                    .addRequestHeader("User-Agent", DEFAULT_UA)
                    .addRequestHeader("Referer", "https://www.douyin.com/")
                    .addRequestHeader("Accept", "video/*;q=0.9,*/*;q=0.8")

                dm.enqueue(req)
                requireActivity().runOnUiThread {
                    Toast.makeText(requireContext(), "已开始下载：$fileName", Toast.LENGTH_SHORT).show()
                }
            } catch (e: Exception) {
                requireActivity().runOnUiThread {
                    Toast.makeText(requireContext(), "下载失败：${e.message}", Toast.LENGTH_SHORT).show()
                }
            }
        }.start()
    }

    /**
     * 根据 URL 生成文件名。
     * - 优先取路径最后一段，否则用时间戳。
     */
    private fun buildFileName(url: String): String {
        return try {
            val path = Uri.parse(url).lastPathSegment ?: System.currentTimeMillis().toString()
            val base = if (path.contains('.')) path.substringBeforeLast('.') else path
            "$base.mp4"
        } catch (e: Exception) {
            System.currentTimeMillis().toString() + ".mp4"
        }
    }

    /**
     * 预检响应头信息，优先使用 HEAD，失败时降级 Range GET。
     */
    private fun fetchHeadInfo(urlStr: String): HeadInfo? {
        return try {
            var conn = (URL(urlStr).openConnection() as HttpURLConnection)
            conn.instanceFollowRedirects = true
            conn.requestMethod = "HEAD"
            conn.setRequestProperty("User-Agent", DEFAULT_UA)
            conn.setRequestProperty("Referer", "https://www.douyin.com/")
            conn.connectTimeout = 10000
            conn.readTimeout = 10000
            val code = conn.responseCode
            Log.d(TAG, "HEAD status=$code url=${conn.url}")
            if (code !in 200..399) {
                conn.disconnect()
                conn = (URL(urlStr).openConnection() as HttpURLConnection)
                conn.requestMethod = "GET"
                conn.setRequestProperty("Range", "bytes=0-0")
                conn.setRequestProperty("User-Agent", DEFAULT_UA)
                conn.setRequestProperty("Referer", "https://www.douyin.com/")
                conn.connectTimeout = 10000
                conn.readTimeout = 10000
                val rcode = conn.responseCode
                Log.d(TAG, "Range GET status=$rcode url=${conn.url}")
            }
            val type = conn.getHeaderField("Content-Type")
            val dispo = conn.getHeaderField("Content-Disposition")
            val finalUrl = conn.url?.toString()
            conn.disconnect()
            HeadInfo(finalUrl ?: urlStr, type, dispo)
        } catch (_: Exception) {
            Log.e(TAG, "fetchHeadInfo: failed for $urlStr")
            null
        }
    }

    /**
     * 根据URL/Content-Disposition/Content-Type 推断mp4文件名，确保以 .mp4 结尾。
     */
    private fun guessMp4FileName(url: String, contentDisposition: String?, contentType: String?): String {
        return try {
            val name = URLUtil.guessFileName(url, contentDisposition, contentType)
            val fixed = if (name.endsWith(".mp4", ignoreCase = true)) name else name.substringBeforeLast('.') + ".mp4"
            if (fixed.startsWith(".")) System.currentTimeMillis().toString() + ".mp4" else fixed
        } catch (_: Exception) {
            buildFileName(url)
        }
    }

    /**
     * 预检结构体：存储最终URL、Content-Type与Content-Disposition。
     */
    private data class HeadInfo(val url: String, val contentType: String?, val contentDisposition: String?)

    private companion object {
        const val DEFAULT_UA = "Mozilla/5.0 (Linux; Android 12; Mobile) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Mobile Safari/537.36"
    }
}